from django.contrib.auth.decorators import login_required
from django.db.models import QuerySet
from django.forms import modelformset_factory, formset_factory
from django.http import JsonResponse, HttpResponseRedirect, Http404
from django.shortcuts import render, get_object_or_404, get_list_or_404, redirect
from django.views.generic.edit import CreateView, UpdateView, DeleteView, \
    FormView
from django.views.generic import ListView, DetailView
from .forms import *
from django.urls import reverse_lazy
from django.utils.decorators import method_decorator
from .models import *
from review.engine.util import *
from review.engine.rgit import *


# A discussion about where to put business logic:
#   https://forum.djangoproject.com/t/where-to-put-business-logic-in-django/282/13

# Create your views here.
@login_required
def index(request):
    return render(request, 'review/index.html', {})


def api_token_required(func):
    def check_token(*args, **kwargs):
        review_user = ReviewUser.objects.filter(user=args[0].user)
        if not review_user.exists() or review_user.first().review_api_token.isspace():
            return redirect('review:userinfo-create')
        else:
            return func(*args, **kwargs)

    return check_token


decorators = [login_required]


@login_required
def review_user_info_view(request):
    if not ReviewUser.objects.filter(user=request.user).exists():
        url = 'review:userinfo-create'
    else:
        url = 'review:userinfo-detail'

    return redirect(url)


@method_decorator(decorators, name='dispatch')
class ReviewUserInfoDetailView(DetailView):
    context_object_name = "review_userinfo"
    template_name = "review/review_user_info.html"
    model = ReviewUser

    def get_object(self, queryset=None):
        return get_object_or_404(ReviewUser, user_id=self.request.user.id)


@method_decorator(decorators, name='dispatch')
class ReviewUserInfoFormCreateView(CreateView):
    template_name = 'review/review_user_info_form.html'
    form_class = ReviewUserInfoForm
    success_url = reverse_lazy('review:userinfo')

    def get_initial(self):
        self.initial.update({
            'user': self.request.user
        })
        return super(ReviewUserInfoFormCreateView, self).get_initial()


@method_decorator(decorators, name='dispatch')
class ReviewUserInfoFormUpdateView(UpdateView):
    template_name = 'review/review_user_info_form.html'
    form_class = ReviewUserInfoForm
    success_url = reverse_lazy('review:userinfo')

    def get_initial(self):
        self.initial.update({
            'user': self.request.user
        })
        return super(ReviewUserInfoFormUpdateView, self).get_initial()

    # def get_form_kwargs(self):
    #     kwargs = super().get_form_kwargs()
    #     kwargs.update({
    #         'user': self.request.user
    #     })
    #     return kwargs

    def get_object(self, queryset=None):
        return get_object_or_404(ReviewUser, user_id=self.request.user.id)


@method_decorator(decorators, name='dispatch')
class ReviewProfileListView(ListView):
    context_object_name = "review_profile_list"
    template_name = "review/review_profile_list.html"
    model = ReviewProfile
    paginate_by = 6

    def get_queryset(self):
        return ReviewProfile.objects.filter(user_id=self.request.user.id)


@method_decorator(decorators, name='dispatch')
class ReviewProfileFormCreateView(CreateView):
    template_name = 'review/review_profile_form.html'
    form_class = ReviewProfileForm
    success_url = reverse_lazy('review:profile-list')
    extra_context = {
        'extra_groups': get_group_name_list(),
        'extra_people': get_people_name_list(),
        'extra_repositories': get_repository_name_list(),
    }

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs.update({
            'opera_type': ReviewProfileForm.PROFILE_CREATE,
        })
        return kwargs

    def get_initial(self):
        self.initial.update({
            'user': self.request.user,
        })
        # if self.request.method == 'GET':
        #     self.initial.update({
        #         'profile_name': '',
        #         'review_branch': '',
        #     })
        return super(ReviewProfileFormCreateView, self).get_initial()


@method_decorator(decorators, name='dispatch')
class ReviewProfileFormUpdateView(UpdateView):
    template_name = 'review/review_profile_form.html'
    form_class = ReviewProfileForm
    model = ReviewProfile
    success_url = reverse_lazy('review:profile-list')
    # extra_context = {
    #     'extra_groups': get_group_name_list(),
    #     'extra_people': get_people_name_list(),
    #     'extra_repositories': get_repository_name_list(),
    # }

    # def get_queryset(self):
    #     return ReviewProfile.objects.filter(user_id=self.request.user.id)

    def get(self, request, *args, **kwargs):
        ret = super(ReviewProfileFormUpdateView, self).get(request, *args, **kwargs)
        obj = self.object
        return ret

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs.update({
            'opera_type': ReviewProfileForm.PROFILE_UPDATE
        })
        return kwargs

    def get_initial(self):
        self.initial.update({
            'user': self.request.user,
        })
        return super(ReviewProfileFormUpdateView, self).get_initial()


@method_decorator(decorators, name='dispatch')
class ReviewProfileFormDeleteView(DeleteView):
    model = ReviewProfile
    success_url = reverse_lazy('review:profile-list')
    template_name = 'review/review_profile_form.html'

    def get_queryset(self):
        return ReviewProfile.objects.filter(user_id=self.request.user.id)


@method_decorator(decorators, name='dispatch')
class ReviewFormListView(ListView):
    template_name = 'review/review_list.html'
    context_object_name = "review_list"
    paginate_by = 6

    def paginate_queryset(self, queryset, page_size):
        paginator, page, queryset, is_paginated = super(ReviewFormListView, self).paginate_queryset(queryset, page_size)
        client = ReviewClient({'user': self.request.user})
        for r in queryset:
            if r.review_id != 0:
                cnt = client.get_ship_it_count(r.review_id)
                r.ship_it_count = cnt
                r.save()
        return paginator, page, queryset, is_paginated

    def get_queryset(self):
        records = ReviewRecord.objects.filter(user=self.request.user)
        # client = ReviewClient({'user': self.request.user})
        # for r in records:
        #     if r.review_id != 0:
        #         cnt = client.get_ship_it_count(r.review_id)
        #         r.ship_it_count = cnt
        #         r.save()
        return records


@login_required
@api_token_required
def review_create_presetting_view(request):
    if request.method == 'POST':
        form = ReviewPresettingForm(request.POST)
        if form.is_valid():
            review_num = form.cleaned_data['review_num']
            return HttpResponseRedirect(f'/review/create/{review_num}/')
    else:
        form = ReviewPresettingForm()

    return render(request, 'review/review_presetting_form.html', {'form': form})


@login_required
@api_token_required
def review_form_create_view(request, review_num):
    ReviewFormSet_F = modelformset_factory(
        model=ReviewRecord,
        form=ReviewForm,
        formset=ReviewFormSet,
        extra=review_num
    )

    initial_dict_list = []
    profile_list = ReviewProfile.objects.filter(user_id=request.user.id)
    for i in range(review_num):
        initial_dict_list.append({
            'user': request.user,
        })

    query_set_none = ReviewRecord.objects.none()
    # query_set_this_user = ReviewRecord.objects.filter(user=request.user)
    if request.method == 'POST':
        formset = ReviewFormSet_F(
            data=request.POST,
            files=request.FILES,
            initial=initial_dict_list,
        )
        if formset.is_valid():
            formset.save()
            review_group_id = formset.get_customer_data('review_group_id')
            return HttpResponseRedirect(f'/review/public/{review_group_id}/')
    else:
        formset = ReviewFormSet_F(
            initial=initial_dict_list,
            # queryset=query_set_this_user,
            queryset=query_set_none,
            form_kwargs={'review_profile_list': profile_list}
        )
    return render(request, 'review/review_formset.html', {'formset': formset})


@login_required
@api_token_required
def review_form_public_view(request, group_id):
    ReviewPublicFormSet_F = modelformset_factory(
        model=ReviewRecord,
        form=ReviewPublicForm,
        formset=ReviewPublicFormSet,
        extra=0
    )

    query_set = ReviewRecord.objects.filter(review_group_id=group_id)
    if not query_set.exists():
        raise Http404('No %s matches the given query.' % query_set.model._meta.object_name)

    if request.method == 'POST':
        formset = ReviewPublicFormSet_F(
            data=request.POST,
            files=request.FILES,
            form_kwargs={'opera_type': ReviewPublicForm.REVIEW_CREATE}
        )
        if formset.is_valid():
            formset.save()
            return HttpResponseRedirect('/review/list/')
    else:
        formset = ReviewPublicFormSet_F(
            queryset=query_set,
            form_kwargs={'opera_type': ReviewPublicForm.REVIEW_CREATE}
        )
    return render(request, 'review/review_public_formset.html', {
        'formset': formset,
        # 'type': ReviewPublicForm.REVIEW_CREATE
    })


@method_decorator(decorators, name='dispatch')
@method_decorator(api_token_required, name='dispatch')
class ReviewFormUpdateView(UpdateView):
    template_name = 'review/review_form.html'
    form_class = ReviewPublicForm
    model = ReviewRecord
    success_url = reverse_lazy('review:list')

    def get_queryset(self):
        return ReviewRecord.objects.filter(user_id=self.request.user.id)

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs.update({
            'opera_type': ReviewPublicForm.REVIEW_UPDATE
        })
        return kwargs

    def get_initial(self):
        self.initial.update({
            'user': self.request.user
        })
        return super(ReviewFormUpdateView, self).get_initial()


@login_required
@api_token_required
def review_push_view(request, pk):
    query_set = ReviewRecord.objects.filter(id=pk)
    if not query_set.exists():
        raise Http404('No %s matches the given query.' % query_set.model._meta.object_name)
    elif query_set.count() != 1:
        raise Http404('Multiple %s matches the given query.' % query_set.model._meta.object_name)

    if request.method == 'POST':
        obj = query_set.first()
        repo = get_local_repo(obj.review_profile.review_repository)
        git = RGit(repo)
        git.config_name_and_email(obj.user.name, obj.user.email)
        git.update()
        if not str(obj.review_branch).isspace():
            for br in obj.review_branch.split(','):
                git.switch_branch(br)
                git.apply(obj.final_patch)
                git.commit(obj.review_description)
                git.push()
    else:
        ...
